# -*- coding: utf-8 -*-
import pytest
import base64
import hashlib
import logging
import pprint
import re
import time
import warnings
from datetime import datetime, timedelta
import os
import sys

sys.path.append(os.path.abspath('.'))

from conftest import *

import requests
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding

from conf.read_conf import *


def get_log_filename(log_path, prefix, extension='.log'):
    """根据当前日期生成日志文件名"""
    today = datetime.now().strftime('%Y-%m-%d')
    return os.path.join(log_path, f"{prefix}_{today}{extension}")


# 创建Logger对象
logger = logging.getLogger('API')
logger.setLevel(logging.INFO)

# 处理日志路径，尝试几个个相对路径中找到第一个存在的路径，找到则将该路径赋值给 log_dir 变量，否则 log_dir 被赋值为 None。
log_dir = next((path for path in ['./log', '../log', '../../log'] if os.path.exists(path)), None)

# 如果没有找到有效的日志路径，则创建一个新的日志文件夹  
if log_dir is None:
    log_dir = './log'  # 设置默认日志路径  
    os.makedirs(log_dir, exist_ok=True)  # 创建日志文件夹  

# 获取当前日期的日志文件名
info_log_filename = get_log_filename(log_dir, 'info')
error_log_filename = get_log_filename(log_dir, 'error')

file_handler = logging.FileHandler(info_log_filename, encoding='utf-8')
file_handler.setLevel(logging.INFO)

error_file_handler = logging.FileHandler(error_log_filename, encoding='utf-8')
error_file_handler.setLevel(logging.ERROR)

# 创建控制台Handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setLevel(logging.ERROR)

# 创建Formatter，并将其添加到Handler
formatter = logging.Formatter('[%(asctime)s] %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
error_file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# 将文件Handler、错误文件Handler和控制台Handler添加到Logger
logger.addHandler(file_handler)
logger.addHandler(error_file_handler)
logger.addHandler(console_handler)


# 哈希256加密
def sha256str(strings):
    sha256 = hashlib.sha256()
    sha256.update(strings.encode('utf-8'))
    return sha256.hexdigest()


# 获取13位时间戳
def get_timestamp():
    return str(int(time.time() * 1000))


# rsa加密通用加密方法，传入公钥配置：rsaPublicKey_externaApi（对外）、rsaPublicKey（内部）
def rsa_encrypt(password_str, public_key_config_name):
    password_str = password_str.encode()
    decoded_public_key = base64.b64decode(read_conf(envs_test, public_key_config_name))
    public_key = serialization.load_der_public_key(decoded_public_key)
    cipher_password = public_key.encrypt(password_str, padding.PKCS1v15())
    return base64.b64encode(cipher_password).decode('utf-8')


# 对外接口rsa加密
def rsa_encode(password_str):
    return rsa_encrypt(password_str, 'rsaPublicKey_externaApi')


# 内部接口rsa加密
def rsa_internal_api_encode(password_str):
    return rsa_encrypt(password_str, 'rsaPublicKey')


def login(email12, password1):
    url = cs_url + "/CodeSecInterfaceService/login/user"
    # 内部接口rsa加密
    password_rsa = rsa_internal_api_encode(password1)
    json = {
        "email": email12,
        "password": password_rsa
    }
    r = requests.post(url=url, data=json)
    response_json = r.json()
    # print(response_json)
    authorization = response_json['userInfo']['authorization']
    loginNonce = response_json['userInfo']['loginNonce']
    userId = response_json['userInfo']['id']
    token = response_json['token']
    if 'userOrg' in response_json['userInfo']:
        orgUuid = response_json['userInfo']['userOrg']['orgUuid']
        return authorization, loginNonce, userId, token, orgUuid
    else:
        return authorization, loginNonce, userId, token










def login_email(email_str, password_str):
    url = cs_url + "/CodeSecInterfaceService/login/user"
    # 内部接口rsa加密
    password_rsa = rsa_internal_api_encode(password_str)
    json = {
        "email": email_str,
        "password": password_rsa
    }
    r = requests.post(url=url, data=json)
    response_json = r.json()
    return response_json


# 登录,返回内部接口请求头
def login_header(email_str, password_str):
    execute_sqlfile(f"C:/Users/Administrator/Desktop/d/sql.sql")
    sql = f"SELECT * FROM `ssp_v4`.`autotest_user_token` where email = '{email_str}' ORDER BY `id` DESC;"
    user_token = execute_sql(sql)
    if "()" in str(user_token):
        print("新建的autotest_user_token表，无数据!登录后，token信息入库！")
        response_json = login_email(email_str, password_str)
        authorization = response_json['userInfo']['authorization']
        loginNonce = response_json['userInfo']['loginNonce']
        userId = response_json['userInfo']['id']
        token = response_json['token']
        sql2 = f"INSERT INTO autotest_user_token (email, authorization, loginNonce, userId, token) VALUES ('{email_str}', '{authorization}', '{loginNonce}', '{userId}', '{token}');"
        execute_sql(sql2)
        # execute_sqlfile(f"C:/Users/Administrator/Desktop/d/sql2.sql")

    else:
        authorization = user_token[0]['authorization']
        loginNonce = user_token[0]['loginNonce']
        userId = user_token[0]['userId']
        token = user_token[0]['token']
        # expires_at = user_token[0]['expires_at']
        created_at = user_token[0]['created_at']
        print("\n使用数据库token!")
        print(user_token)

    # 获取当前时间，并去掉小数部分
    # current_time = datetime.now()
    #
    # # 计算 30 分钟前的时间，并去掉小数部分
    # t = created_at + timedelta(minutes=30)
    # print("过期时间", t)

    # 检查 created_at 是否在当前时间的 30 分钟内
    # if current_time > t:
    #     url = cs_url + "/CodeSecInterfaceService/login/user"
    #     # 内部接口rsa加密
    #     password_rsa = rsa_internal_api_encode(password_str)
    #     json = {
    #         "email": email_str,
    #         "password": password_rsa
    #     }
    #     r = requests.post(url=url, data=json)
    #     response_json = r.json()



    timestamp = get_timestamp()
    secret = "UmVwbGF5RGVmZW5zZQ=="  # 固定sign验签参数
    sign = hashlib.sha256((timestamp + secret).encode()).hexdigest()  # 生成sign验签

    headers_str = {
        "authorization": authorization,
        "loginNonce": loginNonce,
        "userId": userId,
        "token": token,
        'timestamp': timestamp,
        'sign': sign,
        'lang': lang
    }

    return headers_str


headers = login_header(email, password)


def getPathValue(base_path):
    # 定义函数getPathValue，接收base_path参数
    if base_path is not None:
        parameters = base_path.split("/")
        # 将base_path按"/"分割后的结果赋值给parameters
        if len(parameters) == 6:
            if 'project'.__eq__(parameters[1]):
                # 如果第二个元素与'project'相等
                return parameters[2] + "&" + parameters[4]

        elif len(parameters) == 4:
            if 'user'.__eq__(parameters[1]) | 'project'.__eq__(parameters[1]):
                # 如果第二个元素为'user'或'project'
                return parameters[2]
        elif len(parameters) == 3:
            # 如果parameters的长度为3
            return ""


def getSignatureHeader(access_secret, times_tamp, x_cs_nonce_str):
    return "&" + access_secret + "&" + str(times_tamp) + "&" + x_cs_nonce_str


def handDict(my_dict):
    # 定义函数handDict，接收参数my_dict
    if isinstance(my_dict, dict):
        sorted_keys = sorted(my_dict)
        # 对字典的键进行排序
        my_str_list = []
        for k in sorted_keys:
            v = my_dict[k]
            if isinstance(v, list):
                # 如果值是列表，则处理列表中的每个元素
                v_str_list = ['["{}"]'.format(handDict(item)) if isinstance(item, (str, int, float)) else str(item) for
                              item in v]
                # 假设我们只对基本数据类型（如str, int, float）加[""]，对于其他类型直接转为字符串
                my_str_list.append('{}={}'.format(k, ','.join(v_str_list)))
            elif v:
                # 如果值非空且不是列表，则递归处理
                my_str_list.append('{}={}'.format(k, handDict(v)))
        # 使用"&"连接生成最终的字符串
        return "&".join(my_str_list)

    elif isinstance(my_dict, list):
        # 如果传入的是列表（但根据原始逻辑，这里实际上不应该被调用）
        # 我们可以假设这是处理字典值时遇到的列表，但按照要求，我们已在字典处理中处理这种情况
        # 这里保留原始逻辑以展示如何处理列表（尽管在函数中不太可能直接调用）
        my_str = ','.join(str(item) for item in my_dict)
        return my_str
    else:
        # 对于基本数据类型或不需要特殊处理的类型，直接转为字符串
        return str(my_dict)


# 获取对外接口请求头
def external_header(parameter, base_path=None, email_str=email, password_str=password):
    openToken = create_opentoken(email_str=email_str, password_str=password_str)
    signatureStr = handDict(parameter)
    timestamp = get_timestamp()  # 解决时间戳不一致问题
    # 当base_path存在时，需要加入
    # if base_path:
    signatureStr += "&" + str(getPathValue(base_path))
    signatureStr += getSignatureHeader(openToken, timestamp, x_cs_nonce)
    if signatureStr[0] == '&':  # 去除首字符的&
        signatureStr = signatureStr[1:]
    signatureStr = signatureStr.replace("&&", "&")  # 对连续的&&去重
    # print("signatureStr: " + signatureStr)
    signature = sha256str(signatureStr)
    userId = login_header(email_str=email_str, password_str=password_str)['userId']
    req_header = {
        'accessKey': userId,  # 用户ID
        'x-cs-timestamp': timestamp,  # 时间戳
        'x-cs-nonce': x_cs_nonce,  # 随机数
        'x-cs-signature': signature,  # 签名
        'lang': lang  # 语言
    }
    return req_header, signatureStr


def send_request(url=None, method=None, parameter=None, base_path=None, email_user=email, password_str=password):
    warnings.simplefilter("ignore", ResourceWarning)  # 忽略ResourceWarning警告
    #  剔除值为None的参数，针对不传参的用例
    for key in list(parameter.keys()):
        if parameter[key].lower() == "none":
            parameter.pop(key)
    # 判断使用外部/内部接口请求头
    if base_path:
        # 外部接口
        header = external_header(parameter, base_path, email_str=email_user, password_str=password_str)[0]
    else:
        # 内部接口
        header = login_header(email_str=email_user, password_str=password_str)
    session = requests.Session()
    response = getattr(session, method.lower())(url=url, json=parameter, params=parameter,
                                                # 动态执行请求方法，除了json和params请求体，还需要考虑data
                                                headers=header)
    response_json = response.json()
    # print(f"请求参数：{header}\n")
    print(f"\n请求接口：{url} \n请求头：{header}\n请求参数：{parameter}\n响应：{response_json}")
    # pprint.pprint(response_json)
    response_status_code = response_json.get('code')

    # 匹配上4、B4、5、B5开头的状态码，输出error日志
    if any(re.match(pattern, str(response_status_code)) for pattern in
           (r'^4\d{2}$', r'^B4\d{2}$', r'^B5\d{2}$', r'^5\d{2}$')):
        log = logging.getLogger('ERROR')
        log.addHandler(error_file_handler)
        log_level = log.error
        log_level(
            f"------------------------------------------请求错误：{response_json['message']}-----------------------------")
    else:
        log = logging.getLogger('API')
        log_level = log.info
        log_level(
            "--------------------------------------------------请求成功--------------------------------------------------")
    log_level("请求url：%s", url)
    log_level("请求头：\n%s", pprint.pformat(header) + "\n")
    log_level("请求参数：\n%s", pprint.pformat(parameter) + "\n")
    if base_path:
        log_level("验签拼接参数：\n%s" + external_header(parameter, base_path)[1] + "\n")
    log_level("返回内容：\n%s", pprint.pformat(response_json) + "\n")
    return response_json


def get_opentoken(email_str=email, password_str=password):
    url = cs_url + "/CodeSecInterfaceService/user/token/select"
    headers2 = login_header(email_str=email_str, password_str=password_str)
    response = requests.get(url=url, headers=headers2)
    response_json = response.json()
    # 判断 openToken 是否存在
    if 'data' in response_json and 'openToken' in response_json['data']:
        openToken = response_json['data']['openToken']
    else:
        openToken = None
    return openToken


# 判断不存在opentoken，创建opentoken
def create_opentoken(email_str=email, password_str=password):
    openToken = get_opentoken(email_str=email_str, password_str=password_str)
    if openToken is None:
        url = cs_url + "/CodeSecInterfaceService/user/openToken/create"
        # 列表入参
        nameValueList = [
            ("openTypeIds", "5"),
            ("openTypeIds", "1"),
            ("openTypeIds", "9"),
            ("openTypeIds", "7"),
            ("openTypeIds", "4"),
            ("openTypeIds", "10"),
            ("openTypeIds", "2"),
            ("openTypeIds", "6"),
            ("openTypeIds", "11"),
            ("expiredDate", "2099-12-06 23:59:59")
        ]
        response = requests.post(url=url, headers=headers, data=nameValueList)
        response_json = response.json()
        # print("更新opentoken：",response_json)
        openToken = response_json['openToken']
        # userId = headers['userId']
        # return openToken, userId
        return openToken

    else:
        # print("已存在opentoken：",openToken)
        # userId = headers['userId']
        # return openToken, userId
        return openToken


if __name__ == '__main__':
    # create_opentoken()
    # e = rsa_internal_api_encode("Seczone@123")
    # print(e)
    # print(create_opentoken())
    # print(rsa_encode("glpat-W8uiQHMfqCxhz6A74UBn"))
    print(get_opentoken())
